import os, subprocess
import random, string
import filecmp
import time
from tkinter import *
from tkinter.filedialog import askopenfilename, askopenfilenames, askdirectory, asksaveasfilename
import tkinter.messagebox as messagebox

def GetSize(path): 
	size=0
	if os.path.isfile(path):
		size = os.path.getsize(path)
	elif os.path.isdir(path):
		for root, dirs, files in os.walk(path):
			for f in files:
				size += os.path.getsize(os.path.join(root, f))
	return size

def timestr():
	return time.strftime("%Y%m%d_%H%M%S", time.localtime(time.time()))

def mv(src, dst):
	cmd='move \"'+src+'\" \"'+dst+'\"'
	print(cmd)
	res = os.popen(cmd).readlines()
	print(str(res))
	# os.system('pause')

def rd(dir):
	cmd='rd /s /q \"'+dir+'\"'
	print(cmd)
	res = os.popen(cmd).readlines()
	print(str(res))
	
def makeAccess(dir):
	cmd='attrib /s /d -r -s -h \"'+dir+'\\*.*\"'
	print(cmd)
	res = os.popen(cmd).readlines()
	print(str(res))
	
def fc(p1, p2):
	cmd='fc /B \"'+p1+'\" \"'+p2+'\"'
	print(cmd)
	res = os.popen(cmd).readlines()
	print(str(res))
	
	
def rm(path):
	cmd='del \"'+path+'\"'
	print(cmd)
	res = os.popen(cmd).readlines()
	print(str(res))
	
def rar1(pathin, pathout, pw=''):
	cmd='\"C:\\Program Files\\WinRAR\\Rar.exe\" x \"'+pathin+'\" \"'+pathout+'\\\"'
	# cmd='\"C:\\Program Files\\WinRAR\\WinRAR.exe\" x \"'+pathin+'\" \"'+pathout+'\\\"'
	if len(pw)>0:
		cmd=cmd+' -p'+pw
	print(cmd)
	res = os.popen(cmd).readlines()
	print(str(res))
	# print(res[-1])
	return res
	
def rar(pathin, pathout, pw=''):
	# cmd='\"C:\\Program Files\\WinRAR\\Rar.exe\" x \"'+pathin+'\" \"'+pathout+'\\\"'
	cmd='\"C:\\Program Files\\WinRAR\\WinRAR.exe\" x \"'+pathin+'\" \"'+pathout+'\\\" -inul'
	if len(pw)>0:
		cmd=cmd+' -p\"'+pw+'\"'
	print(cmd)
	# res = os.popen(cmd).readlines()
	res,msg= subprocess.getstatusoutput(cmd)
	print(str(res))
	print(str(msg))
	# print(res[-1])
	return res


	
def randstr(num=8):
	return ''.join(random.sample(string.ascii_letters+string.digits, num))

def tempname(dir):
	name=randstr(4)
	while os.path.exists(os.path.join(dir,name)):
		name=randstr(4)
	return name

def mvdir(pathsrc, pathdst):
	folder, name=os.path.split(pathsrc)
	if folder==pathdst:
		folder2, name2=os.path.split(pathdst)
		nametmp=tempname(folder2)
		pathtmp=os.path.join(folder2, nametmp)
		mv(pathsrc, pathtmp)
		rd(folder)
		mv(pathtmp, pathdst)
	else:
		if os.path.exists(pathdst):
			print(pathdst+' exists, no move')
		else:
			mv(pathsrc, pathdst)
			rd(folder)

def up(dir):
	print(dir)
	try:
		fl=os.listdir(dir)
	except Exception as ex:
		fl=[]
	print(str(fl))
	if len(fl)==1:
		print('up folder '+dir)
		folder, name=os.path.split(dir)
		pathsrc=os.path.join(dir, fl[0])
		if os.path.isdir(pathsrc):
			pathdst=dir+'_'+fl[0]
			if len(fl[0])>len(name):
				found=fl[0].find(name)
				if found>=0:
					pathdst=os.path.join(folder,fl[0])
			else:
				found=name.find(fl[0])
				if found>=0:
					pathdst=dir
			mvdir(pathsrc, pathdst)
		elif os.path.isfile(pathsrc):
			fname, fext=os.path.splitext(fl[0])
			pathdst=dir+'_'+fl[0]
			if len(fname)>len(name):
				found=fname.find(name)
				if found>=0:
					pathdst=os.path.join(folder,fl[0])
			else:
				found=name.find(fname)
				if found>=0:
					pathdst=dir+fext
			mvdir(pathsrc, pathdst)
		else:
			pass
			
			
def myrar(pathin, pw=''):
	ret=False
	name, ext=os.path.splitext(pathin)
	if os.path.exists(name):
		print(name+' exists, no unrar')
	else:
		res=rar(pathin, name, pw)
		# if len(res)>0 and res[-1]=='全部正常\n':
		if res==0:
			if os.path.exists(name) and os.path.isdir(name):
				up(name)
				rm(pathin)
				ret=True
		else:
			rd(name)
	return ret

	
def myrarMany(pathin, pwlist, compressRatioThres=2):
	ret=False
	name, ext=os.path.splitext(pathin)
	if os.path.exists(name):
		print(name+' exists, no unrar')
	else:
		for pw in pwlist:
			res=rar(pathin, name, pw)
			# if len(res)>0 and res[-1]=='全部正常\n':
			if res==0:
				if os.path.exists(name) and os.path.isdir(name):
					rarbyte=GetSize(pathin)
					unrarbyte=GetSize(name)
					if unrarbyte>rarbyte*compressRatioThres:
						rd(name)
					else:
						up(name)
						rm(pathin)
						ret=True
						break
			else:
				rd(name)
	return ret
	
def passall(dir, pw):
	ret=False
	fl=os.listdir(dir)
	for fli in fl:
		path=os.path.join(dir, fli)
		if os.path.isfile(path):
			name, ext=os.path.splitext(fli)
			if ext.lower()=='.rar' or ext.lower()=='.zip' or ext.lower()=='.7z':
				print('trying '+path)
				ret|=myrarMany(path, pw)
		elif os.path.isdir(path):
			ret|=passall(path, pw)
		else:
			pass
	return ret

def loopall(dir, pw):
	while passall(dir, pw):
		pass
			
			
def typeStr(path):
	if os.path.isfile(path):
		return 'file'
	elif os.path.isdir(path):
		return 'folder'
	else:
		return 'unknown'
			
def CleanTargetDuplicate(refer, target, dupList):
	try:
		fl=os.listdir(target)
	except Exception as ex:
		fl=[]
	for fn in fl:
		pathRefer=os.path.join(refer, fn)
		pathTarget=os.path.join(target, fn)
		if os.path.exists(pathRefer):
			if os.path.isfile(pathTarget) and os.path.isfile(pathRefer):
				if pathTarget==pathRefer:
					print('skip same file '+pathRefer)
				else:
					if filecmp.cmp(pathTarget,pathRefer):
						print('remove file copy '+str(pathTarget))
						try:
							os.remove(pathTarget)
							dupList.append(pathTarget)
						except Exception as ex:
							print('fail remove file copy '+str(pathTarget))
					else:
						print('find file diff '+str(pathTarget))
			elif os.path.isdir(pathTarget) and os.path.isdir(pathRefer):
				CleanTargetDuplicate(pathRefer, pathTarget, dupList)
			else:
				print('no match '+typeStr(pathTarget)+' '+str(pathTarget)+' to '+typeStr(pathRefer)+' '+str(pathRefer))
		else:
			print('no match '+typeStr(pathTarget)+' '+str(pathTarget)+', '+str(pathRefer)+' not exists')
			
def CleanTargetDuplicateA(refer, target, log):
	duplist=[]
	CleanTargetDuplicate(refer, target, duplist)
	# print(str(duplist))
	with open(log, 'w', encoding='utf-8') as f:
		f.write('duplicate list of '+target+' refer to '+refer+'\r\n')
		for dup in duplist:
			f.write(dup+'\r\n')

def CleanEmptyDir(folder, emptyList):
	try:
		fl=os.listdir(folder)
		if len(fl)<1:
			print('remove empty dir '+folder)
			os.rmdir(folder)
			emptyList.append(folder)
		else:
			for fn in fl:
				path=os.path.join(folder, fn)
				if os.path.isdir(path):
					CleanEmptyDir(path, emptyList)
	except Exception as ex:
		print('fail enter dir '+folder)
		
def CleanEmptyDirA(folder, log):
	emptylist=[]
	elen=len(emptylist)
	CleanEmptyDir(folder, emptylist)
	while len(emptylist)>elen:
		print('begin loop')
		elen=len(emptylist)
		CleanEmptyDir(folder, emptylist)
	with open(log, 'w', encoding='utf-8') as f:
		f.write('empty dir list of '+folder+'\r\n')
		for dup in emptylist:
			f.write(dup+'\r\n')

def AllFileList(folder, fileList):
	try:
		fl=os.listdir(folder)
	except Exception as ex:
		fl=[]
	for fn in fl:
		path=folder+'/'+fn
		if os.path.isfile(path):
			fileList.append(path)
			print('file '+path)
		elif os.path.isdir(path):
			AllFileList(path, fileList)
		else:
			print('unknown type '+path)

def AllFileListA(folder):
	fl=[]
	AllFileList(folder, fl)
	return fl
		
def CleanTargetDuplicate1v1(refer, target, log):
	listR=AllFileListA(refer)
	listT=AllFileListA(target)
	dupList=[]
	i=1
	for ft in listT:
		for fr in listR:
			if ft == fr:
				print('skip same file '+ft)
			else:
				try:
					if filecmp.cmp(ft,fr):
						print('remove file copy '+ft)
						try:
							os.remove(ft)
							dupList.append(ft)
							break
						except Exception as ex:
							print('fail remove file copy '+ft)
				except Exception as ex:
					print('fail cmp '+ft+' to '+fr)
		print('{}/{}'.format(i, len(listT)))
		i+=1
	with open(log, 'w', encoding='utf-8') as f:
		f.write('duplicate list of '+target+' refer to '+refer+'\r\n')
		for dup in dupList:
			f.write(dup+'\r\n')
					
class Application(Frame):
	def __init__(self, master=None):
		Frame.__init__(self, master)
		self.pack()
		self.createWidgets()

	def createWidgets(self):
		self.nameInput = Entry(self, width=200)
		self.nameInput.pack()
		self.alertButton = Button(self, text='refer', command=self.setRefer, height=2, width=6)
		self.alertButton.pack()
		self.nameInput2 = Entry(self, width=200)
		self.nameInput2.pack()
		self.alertButton2 = Button(self, text='target', command=self.setTarget, height=2, width=6)
		self.alertButton2.pack()
		self.nameInput3 = Entry(self, width=200)
		self.nameInput3.pack()
		self.alertButton6 = Button(self, text='password', command=self.setPass, height=2, width=8)
		self.alertButton6.pack()
		self.alertButton3 = Button(self, text='unrar', command=self.unrar, height=2, width=6)
		self.alertButton3.pack()
		self.alertButton4 = Button(self, text='CleanTargetDuplicate', command=self.cleanfile, height=2, width=20)
		self.alertButton4.pack()
		self.alertButton7 = Button(self, text='CleanTargetDuplicate1v1', command=self.cleanfile1v1, height=2, width=20)
		self.alertButton7.pack()
		self.alertButton5 = Button(self, text='CleanEmptyDir', command=self.cleandir, height=2, width=20)
		self.alertButton5.pack()
		
	def setPass(self):
		fd=askopenfilename()
		self.nameInput3.delete(0, 'end')
		self.nameInput3.insert(0, fd)
		
	def setRefer(self):
		fd=askdirectory()
		self.nameInput.delete(0, 'end')
		self.nameInput.insert(0, fd)
		
	def setTarget(self):
		#messagebox.showinfo('Message', 'Hello, %s' % name)
		fd=askdirectory()
		self.nameInput2.delete(0, 'end')
		self.nameInput2.insert(0, fd)
		
	def unrar(self):
		folderT = self.nameInput2.get()
		filePW = self.nameInput3.get()
		pwlist=[]
		if os.path.exists(filePW):
			with open(filePW, 'r') as f:
				pwlist=f.readlines()
				pwlist=[pwi[0:-1] for pwi in pwlist if len(pwi)>1]
		if len(pwlist)<1:
			pwlist=['1024']
		print('pwlist='+str(pwlist))
		loopall(folderT, pwlist)
		messagebox.showinfo('complete', 'unrar %s' % folderT)
		
	def cleanfile(self):
		folderR = self.nameInput.get()
		folderR = folderR.replace('/', '\\')
		folderT = self.nameInput2.get()
		folderT = folderT.replace('/', '\\')
		makeAccess(folderT)
		CleanTargetDuplicateA(folderR, folderT, 'dup_'+timestr()+'.txt')
		messagebox.showinfo('complete', 'cleanfile %s' % folderT)
	def cleanfile1v1(self):
		folderR = self.nameInput.get()
		folderR = folderR.replace('/', '\\')
		folderT = self.nameInput2.get()
		folderT = folderT.replace('/', '\\')
		makeAccess(folderT)
		makeAccess(folderR)
		CleanTargetDuplicate1v1(folderR, folderT, 'dup_'+timestr()+'.txt')
		messagebox.showinfo('complete', 'cleanfile1v1 %s' % folderT)
	def cleandir(self):
		folderT = self.nameInput2.get()
		makeAccess(folderT)
		CleanEmptyDirA(folderT, 'emp_'+timestr()+'.txt')
		messagebox.showinfo('complete', 'cleandir %s' % folderT)
		
if __name__=='__main__':
	app = Application()
	app.master.title('my file')
	app.mainloop()
